
// Copyright (c) WanSheng Intelligent Corp. All rights reserved.
// Licensed under the LGPL v3.0 license. 


#include "modbus_plugin.h"
#include "parson_ext.h"
#include <math.h>
#include "cJSON.h"

#define PROPERTY_TEXT_LEN 100


float coding_convert(mb_coding_e coding, uint16_t* p, uint32_t* coverted_num)
{
    float v;
    unsigned char* c = (unsigned char*)p;
    const char* sz_coding = modbus_coding_text(coding);
    TraceV(FLAG_VALUE_CONVERT, "coding_convert: ORG: [%02X %02X %02X %02X]",
        c[0], c[1], c[2], c[3]);

    if ((coding == Coding_F_abcd) || (coding == Coding_I_abcd))
        v = my_modbus_get_float_abcd((const uint16_t*)p, coverted_num);
    else if ((coding == Coding_F_dcba) || (coding == Coding_I_dcba))
        v = my_modbus_get_float_dcba((const uint16_t*)p, coverted_num);
    else if ((coding == Coding_F_badc) || (coding == Coding_I_badc))
        v = my_modbus_get_float_badc((const uint16_t*)p, coverted_num);
    else if ((coding == Coding_F_cdab) || (coding == Coding_I_cdab))
        v = my_modbus_get_float_cdab((const uint16_t*)p, coverted_num);
    else
    {
        assert(1);
        return -1;
    }

    c = (unsigned char*)coverted_num;

    TraceV(FLAG_VALUE_CONVERT, "coding_convert: AFTER coding: %s, [%02X %02X %02X %02X] --> %f, %ld",
        sz_coding, c[0], c[1], c[2], c[3], v, *coverted_num);

    return v;
}


/*
 * modbus lib already done the net to host word order conversion
 * need to get it back to net order before doing conversion here!
 */

bool convert_register_to_payload(char* buffer_in,
    char* payload,
    int payload_len,
    mb_coding_e coding,
    double* value_out)
{
    bool need_float_fmt = false;

    uint16_t* p = (uint16_t*)buffer_in;
    uint32_t coverted_num;
    double v ;

    if (MB_CODING_IS_VALID(coding))
    {
        float fv = coding_convert(coding, p, &coverted_num);
        if (MB_CODING_IS_FLOAT(coding))
        {
            float_to_str(fv, 6, payload, payload_len);
        }        
    }
    else
    {
        uint32_t val = 0;
        val = *((uint16_t*)p);
        snprintf(payload, payload_len, "%u", val);
        v = (double) val; 
    }

    if (value_out) *value_out = v;

    return true;
}



char* read_command_from_modbus(i_modbus_command_t* cmd, int* fmt, int* payload_len)
{
    char* out = NULL;
    i_modbus_t* bus = cmd->bus;
    int item_regs = 1;
    char* payload = NULL;
    int rc = 0;

    if (MB_CODING_IS_VALID(cmd->coding))
    {
        item_regs = 2;
    }
    int nb = item_regs * cmd->item_cnt;
    out = malloc(nb * 2);
    if(!out) goto end;

    bus->current_slave_id = cmd->slave_id;
    rc = exec_modbus_command(bus, cmd->fc, cmd->addr, nb, NULL, out);
    if (rc == -1)
    {
        goto end;
    }

    if (cmd->item_cnt > 1)
    {
        cJSON* root_object = cJSON_CreateArray();

        for (int i = 0; i < cmd->item_cnt; i++)
        {
            if (is_coil_fc(cmd->fc))
            {
                cJSON_AddItemToArray(root_object, cJSON_CreateNumber(out[i]));
            }
            else
            {
                double v = 0;
                char payload2[100];
                convert_register_to_payload((char*)(out + (i * item_regs * 2)),
                    payload2, sizeof(payload2),
                    cmd->coding, &v);
                cJSON_AddItemToArray(root_object, cJSON_CreateNumber(v));
            }
        }

        payload = cJSON_Print(root_object);
        *payload_len = (int)strlen(payload);
        cJSON_Delete(root_object);

        *fmt = IA_APPLICATION_JSON;
    }
    else
    {
        if (MODBUS_FC_READ_COILS == cmd->fc || MODBUS_FC_READ_DISCRETE_INPUTS == cmd->fc)
        {
            payload = malloc(10);
            sprintf(payload, "%d", out[0]);
            (*payload_len) = strlen(payload);
        }
        else
        {
            payload = malloc(PROPERTY_TEXT_LEN);
            convert_register_to_payload(out,
                payload, PROPERTY_TEXT_LEN,
                cmd->coding,
                NULL);

            *payload_len = (int)strlen(payload);
        }
        *fmt = IA_TEXT_PLAIN;
    }
end:
    return payload;
}
